package com.iris.live.services.report;

import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.xssf.usermodel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Created by 林平 on 2016/12/9.
 */
@Component("ExcelReportService")
public class ExcelReportServiceImpl implements IExcelReportService {
    private static final Logger logger = LoggerFactory.getLogger(ExcelReportServiceImpl.class);


    @Override
    public void export(ExcelReportContext context, OutputStream os) throws Exception {
        XSSFWorkbook xWorkbook = this.getWorkbook(context);

        xWorkbook.write(os);

        xWorkbook = null;
    }

    @Override
    public void export(ExcelReportContext context, HttpServletResponse response) throws Exception {
        XSSFWorkbook xWorkbook = this.getWorkbook(context);
        if(xWorkbook == null) {
            return;
        }

        response.setContentType("application/vnd.ms-excel");
        String downFileName = context.getFileName();
        String inlineType = "attachment";
        response.setHeader("Content-Disposition", inlineType
                + ";filename=\"" + downFileName + "\"");

        OutputStream os = response.getOutputStream();
        xWorkbook.write(response.getOutputStream());
        os.close();
    }

    private XSSFWorkbook getWorkbook(ExcelReportContext context) throws Exception {
        String template = context.getTemplate();
        Map<String, Object> params = context.getParams();
        IExcelReportSource source = context.getSource();
        boolean staticSheet = context.isStaticSheet();

        XSSFWorkbook xWorkbook = null;

        InputStream templateis = null;
        try {
            logger.info(String.format("Creating excel report for template=%s", template));

            //获取报表模板
            templateis = this.getClass().getClassLoader().getResourceAsStream(template);
            xWorkbook = new XSSFWorkbook(templateis);
            XSSFFormulaEvaluator eval = new XSSFFormulaEvaluator(xWorkbook);

            //生成报表Sheet
            Sheet[] sheets = source.getSheets(context.getParams());
            if (sheets == null) {
                logger.warn("Sheet is not provided.");
                return null;
            }

            if (!staticSheet) {
                createSheet(xWorkbook, context, sheets);
            }

            //输出每个SHEET的内容
            List<Integer> formularRows = new ArrayList<>();
            for (Sheet sheet : sheets) {
                XSSFSheet xSheet = xWorkbook.getSheet(sheet.getName());

                //初始化当前sheet需要输出的数据
                List<Row> rows = source.getSheetRows(params, sheet);
                if (rows == null || rows.isEmpty()) {
                    logger.warn(String.format("No rows got for sheet=%s", sheet.getName()));
                    continue;
                }

                //按行输出内容
                formularRows.clear();
                for (int rowIndex = 0; rowIndex < rows.size(); rowIndex++) {
                    Row row = rows.get(rowIndex);
                    XSSFRow xRow = xSheet.getRow(rowIndex);
                    if (context.isAutoRowExtended() && xRow == null) {
                        xRow = xSheet.createRow(rowIndex);

                        for (int cellIndex = context.getStartCellIndex(); cellIndex < context.getEndCellIndex(); cellIndex++) {
                            xRow.createCell(cellIndex);
                        }
                    }
                    if(row.isHidden()&&xRow!=null) {
                        xRow.setZeroHeight(true);
                    }
                    if (row.isFormular()) { //如果是公式行
                        formularRows.add(rowIndex);
                    } else {
                        Cell[] cells = row.getCells();

                        XSSFCellStyle xssfCellStyle = xWorkbook.createCellStyle();
                        Font font = xWorkbook.createFont();
                        font.setColor(Font.COLOR_RED);
                        xssfCellStyle.setFont(font);
                        xssfCellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
                        if (cells == null) continue;

                        for (Cell cell : cells) {
                            XSSFCell xCell = xRow.getCell(cell.getColIndex());
                            Object value = cell.getValue();

                            if (xCell == null) {
                                continue;
                            }

                            if (value != null) {
                                if (cell.isColorRed()) {
                                    xCell.setCellStyle(xssfCellStyle);
                                }
                                if (cell.getDataType().equals("double")) {
                                    xCell.setCellValue(Double.parseDouble(value.toString()));
                                } else if (cell.getDataType().equals("int")) {
                                    xCell.setCellValue(Integer.parseInt(value.toString()));
                                } else {
                                    xCell.setCellValue(value.toString());
                                }
                            }
                        }
                    }
                }

                if(!formularRows.isEmpty()){
                    for(Integer formularRowIndex : formularRows) {
                        XSSFRow xRow = xSheet.getRow(formularRowIndex);
                        int startCell = xRow.getFirstCellNum(), endCell = xRow.getLastCellNum();
                        for (int i = startCell; i < endCell; i++) {
                            XSSFCell cell = xRow.getCell(i);
                            if (cell == null) continue;

                            if (cell.getCellType() == XSSFCell.CELL_TYPE_FORMULA) {
                                eval.evaluateFormulaCell(cell); //强制刷新公式进行计算
                            }
                        }
                    }
                }
            }
        } catch (Exception xc) {
            logger.error("excel文件导出异常",xc);
        } finally {
            if (templateis != null) {
                templateis.close();
            }
        }

        return xWorkbook;
    }

    /**
     * 根据设置动态创建Sheet
     *
     * @param sheets
     */
    private void createSheet(XSSFWorkbook xWorkbook, ExcelReportContext context, Sheet[] sheets) {
        int index = 0, clonable = context.getClonableSheet();
        for (Sheet sheet : sheets) {
            if(sheet.isClone()){
                if(index > 0) {
                    xWorkbook.cloneSheet(clonable);
                }
            }else{
                xWorkbook.createSheet(sheet.getName());
            }

            xWorkbook.setSheetName(clonable + index, sheet.getName());
            index++;
        }
    }
}
